﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using SharedGenomics.Core;
using SharedGenomics.Domain;
using SharedGenomics.Workbench.Views;
using SharedGenomics.Workbench.PresentationModel;

namespace SharedGenomics.Workbench.Presenters
{
    public class CategoryFilterSetPresenter : Presenter
    {
        private FileSchema _schema;

        public CategoryFilterSetPresenter(ICategoryFilterSetView view, CategoryFilterPresenterFactory categoryFilterPresenterFactory)
            : base(view)
        {
            view.AddCategoryClicked += new EventHandler(this.View_AddCategoryClicked);

            this.FilterSetView = view;
            this.CategoryFilterPresenterFactory = categoryFilterPresenterFactory;

            this.FilterSetView.IsAddCategoryEnabled = false;

            this.FilterPresenters = new List<CategoryFilterPresenter>();
        }

        public void AddCategoryFilter()
        {
            //create a new category filter presenter
            var filterPresenter = this.CategoryFilterPresenterFactory.CreateNew(
                this.Schema.Columns.OfType<NominalFileSchemaColumn>().Select(c => new ValueDisplayItem<string>(c.Name, c.Label ?? c.Name)),
                this.GetColumnValues);

            this.AddCategoryFilter(filterPresenter);
        }

        public void AddCategoryFilter(CategoryFilterPresenter filterPresenter)
        {
            filterPresenter.ThrowIfNull("filterPresenter");

            filterPresenter.FilterRemoved += new EventHandler(this.FilterPresenter_FilterRemoved);
            filterPresenter.FilterAdded += View_AddCategoryClicked;

            this.FilterPresenters.Add(filterPresenter);
            this.FilterSetView.AddFilterView(filterPresenter.FilterView);
        }

        public void ClearFilters()
        {
            while (this.FilterPresenters.Count > 0)
            {
                this.RemoveFilterAt(0);
            }
        }

        private void View_AddCategoryClicked(object sender, EventArgs e)
        {
            this.AddCategoryFilter();
        }

        private void FilterPresenter_FilterRemoved(object sender, EventArgs e)
        {
            CategoryFilterPresenter presenter = (CategoryFilterPresenter)sender;
            int filterIndex = this.FilterPresenters.IndexOf(presenter);

            Debug.Assert(filterIndex != -1);

            this.RemoveFilterAt(filterIndex);
        }

        private void RemoveFilterAt(int filterIndex)
        {
            Debug.Assert(filterIndex.IsBetween(0, this.FilterPresenters.Count - 1, true));

            this.FilterSetView.RemoveFilterAt(filterIndex);

            //remove filter from view and degregister event so it can be garbage collected
            CategoryFilterPresenter presenterToRemove = this.FilterPresenters[filterIndex];
            presenterToRemove.FilterRemoved -= this.FilterPresenter_FilterRemoved;
            presenterToRemove.FilterAdded -= this.View_AddCategoryClicked;

            this.FilterPresenters.RemoveAt(filterIndex);
        }

        private IEnumerable<ValueDisplayItem<string>> GetColumnValues(string columnName)
        {
            return columnName == null
                ? Enumerable.Empty<ValueDisplayItem<string>>()
                : ((NominalFileSchemaColumn)this._schema[columnName]).Values.Select(n => new ValueDisplayItem<string>(n.Value, n.Label??n.Value));
        }

        public virtual FileSchema Schema
        {
            private get { return this._schema; }
            set
            {
                this._schema = value;
                this.FilterSetView.IsAddCategoryEnabled = this._schema != null;
            }
        }

        public virtual IDictionary<string, IEnumerable<string>> CategoricalFilters
        {
            get
            {
                return this.FilterPresenters
                    .Where(fp => fp.SelectedCategory != null)
                    .ToDictionary(fp => fp.SelectedCategory, fp => fp.SelectedValues);
            }
        }

        private IList<CategoryFilterPresenter> FilterPresenters { get; set; }

        private ICategoryFilterSetView FilterSetView { get; set; }
        private CategoryFilterPresenterFactory CategoryFilterPresenterFactory { get; set; }
    }
}
